package orm

import (
	"reflect"
	"strings"
)

// 通过反射获取结构体的字段和对应的数据表列名
type ReflectFieldInfo struct {
	fieldInfo
	s interface{} // 结构体
}

// s 是一个结构体
// 结构体中，靠后的字段优先，可能会覆盖前面的字段
func (ReflectFieldInfo) New(s interface{}) *ReflectFieldInfo {
	t := reflect.TypeOf(s)
	if t.Kind() != reflect.Ptr {
		panic("ReflectFieldInfo.New s的类型必须是指向结构体的指针")
	}
	t = t.Elem()
	if t.Kind() != reflect.Struct {
		panic("ReflectFieldInfo.New s的类型必须是指向结构体的指针")
	}
	inst := &ReflectFieldInfo{
		fieldInfo:getFieldInfo(t),
	}
	inst.s = s
	return inst
}

func (f *ReflectFieldInfo) Fields() []string {
	return f.fs
}

func (f *ReflectFieldInfo) ColumnName(fn string) string {
	return f.fc[fn][0]
}

func (f *ReflectFieldInfo) Column(fn string) (name, table, column string) {
	c := f.fc[fn]
	return c[0], c[1],c[2]
}

func (f *ReflectFieldInfo) GetFieldValue(fn string) interface{} {
	i := f.fi[fn]
	return reflect.ValueOf(f.s).Elem().FieldByIndex(i).Interface()
}

func (f *ReflectFieldInfo) SetFieldValue(fn string, v interface{}) {
	i := f.fi[fn]
	reflect.ValueOf(f.s).Elem().FieldByIndex(i).Set(reflect.ValueOf(v))
}

//type columnInfo struct{
//	Name string
//	Table string
//	Column string
//}

type fieldInfo struct {
	fs []string //字段名
	fi map[string][]int // 字段名对应的字段索引
	fc map[string][3]string // 字段名对应的列名
}

// 根据类型名称缓存字段信息，避免频繁调用反射
var fieldInfoMap = make(map[string]fieldInfo)

func getFieldInfo(t reflect.Type) fieldInfo {
	sn := t.Name()
	if _, ok := fieldInfoMap[sn]; !ok {
		inst := fieldInfo{
			fs: make([]string, 0),
			fi: make(map[string][]int),
			fc: make(map[string][3]string),
		}
		(&inst).append(t)
		fieldInfoMap[sn] = inst
	}
	return fieldInfoMap[sn]
}

func (f *fieldInfo) append(t reflect.Type, index ...int) {
	for i:=0; i< t.NumField(); i++ {
		fs := t.Field(i)
		if fs.Type.Kind() == reflect.Struct {
			f.append(fs.Type, append(index, i)...)
		} else {
			if tag, ok := fs.Tag.Lookup("db"); ok {
				fn := fs.Name
				f.fs = append(f.fs, fn)
				f.fi[fn] = append(index, i)
				f.fc[fn] = [3]string{
					tag,
					fs.Tag.Get("table"),
					fs.Tag.Get("column"),
				}
			}
		}
	}
}

type TableToSetFieldInfoProviderAdapter struct {
	p TableFieldInfoProvider
}

func (a TableToSetFieldInfoProviderAdapter) Fields() []string {
	return a.p.Fields()
}

func (a TableToSetFieldInfoProviderAdapter) Column(f string) (name, table, column string) {
	return a.p.ColumnName(f), "", ""
}

func (a TableToSetFieldInfoProviderAdapter) GetFieldValue(f string) interface{} {
	return a.p.GetFieldValue(f)
}

func (a TableToSetFieldInfoProviderAdapter) SetFieldValue(f string, v interface{}) {
	a.p.SetFieldValue(f, v)
}

func AdaptFieldInfoProvider(meta interface{}) SetFieldInfoProvider {
	if fp, ok := meta.(SetFieldInfoProvider); ok {
		return fp
	} else if fp, ok := meta.(TableFieldInfoProvider); ok {
		return &TableToSetFieldInfoProviderAdapter{p: fp}
	} else {
		return ReflectFieldInfo{}.New(meta)
	}
}

type ColumnReplacer struct {
	fp SetFieldInfoProvider
	e  ExprColumnDefiner
}

func NewColumnReplacer(meta interface{}, fp SetFieldInfoProvider) *ColumnReplacer {
	e, _ := meta.(ExprColumnDefiner)
	return &ColumnReplacer{fp: fp, e: e}
}

// 返回field list中的列语句
func (r *ColumnReplacer) Field(field, name, table, column string) string {
	if r.e !=nil {
		if expr := r.e.Expr(field); expr != "" {
			return expr+" AS `"+name+"`"
		}
	}
	if table == "" {
		if column == "" {
			return "`"+name+"`"
		} else {
			return "`"+column+"` AS `"+name+"`"
		}
	} else {
		if column == "" {
			return "`"+table+"`.`"+name+"`"
		} else {
			return "`"+table+"`.`"+column+"` AS `"+name+"`"
		}
	}
}

// 将field list中的列名替换
func (r *ColumnReplacer) ReplaceField(field, origin, name, table, column string) string {
	return strings.ReplaceAll(origin, "`"+field+"`", r.Field(field, name, table, column))
}

// 将Order中的列名替换
func (r *ColumnReplacer) ReplaceOrder(field, origin, name string) string {
	return strings.ReplaceAll(origin, "`"+field+"`", "`"+name+"`")
}

// 将WHERE条件中的列名替换
func (r *ColumnReplacer) ReplaceCond(field, cond, name, table, column string) string {
	if r.e != nil {
		if expr := r.e.Expr(field); expr != "" {
			return strings.ReplaceAll(cond, "`"+field+"`", expr)
		}
	}
	if table == "" {
		if column == "" {
			return strings.ReplaceAll(cond, "`"+field+"`", "`"+name+"`")
		} else {
			return strings.ReplaceAll(cond, "`"+field+"`", "`"+column+"`")
		}
	} else {
		if column == "" {
			return strings.ReplaceAll(cond, "`"+field+"`", "`"+table+"`.`"+name+"`")
		} else {
			return strings.ReplaceAll(cond, "`"+field+"`", "`"+table+"`.`"+column+"`")
		}
	}
}

/*
// 将field list中的列名替换
func (r *ColumnReplacer) Field(name, table, column string) string {
	if r.e !=nil {
		if expr := r.e.Expr(name); expr != "" {
			return expr+" AS `"+name+"`"
		}
	}
	if table == "" {
		if column == "" {
			return "`"+name+"`"
		} else {
			return "`"+column+"` AS `"+name+"`"
		}
	} else {
		if column == "" {
			return "`"+table+"`.`"+name+"`"
		} else {
			return "`"+table+"`.`"+column+"` AS `"+name+"`"
		}
	}
}

// 将WHERE条件中的列名替换
func (r *ColumnReplacer) ReplaceCond(cond, name, table, column string) string {
	if r.e != nil {
		if expr := r.e.Expr(name); expr != "" {
			return strings.ReplaceAll(cond, "`"+name+"`", expr)
		}
	}
	if table == "" {
		if column == "" {
			return cond
		} else {
			return strings.ReplaceAll(cond, "`"+name+"`", "`"+column+"`")
		}
	} else {
		if column == "" {
			return strings.ReplaceAll(cond, "`"+name+"`", "`"+table+"`.`"+name+"`")
		} else {
			return strings.ReplaceAll(cond, "`"+name+"`", "`"+table+"`.`"+column+"`")
		}
	}
}
*/

